home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / os2 / pmnos11s / popserv.c < prev    next >
C/C++ Source or Header  |  1993-07-30  |  15KB  |  742 lines

  1. /* POP Server state machine - see RFC 937
  2.  *
  3.  *  also see other credits in popcli.c
  4.  *  10/89 Mike Stockett wa7dyx
  5.  *  Modified 5/27/90 by Allen Gwinn, N5CKP, for later NOS releases.
  6.  *  Added to NOS by PA0GRI 2/6/90 (and linted into "standard" C)
  7.  */
  8. #include <stdio.h>
  9. #include <time.h>
  10. #if defined (UNIX) || defined (MSDOS)
  11. #include <sys/types.h>
  12. #endif
  13. #if    defined(__STDC__) || defined(__TURBOC__)
  14. #include <stdarg.h>
  15. #endif
  16. #include <ctype.h>
  17. #include <setjmp.h>
  18. #include "global.h"
  19. #include "mbuf.h"
  20. #include "cmdparse.h"
  21. #include "socket.h"
  22. #include "proc.h"
  23. #include "files.h"
  24. #include "pop.h"
  25.  
  26. extern char Nospace[];
  27.  
  28. static struct pop_scb *create_scb __ARGS((void));
  29. static void delete_scb __ARGS((struct pop_scb *scb));
  30. static void popserv __ARGS((int s,void *unused,void *p));
  31. static int poplogin __ARGS((char *pass,char *username));
  32.  
  33. /* I don't know why this isn't static, it isn't called anywhere else {was} */
  34. void pop_sm __ARGS((struct pop_scb *scb));
  35.  
  36. static int Spop = -1; /* prototype socket for service */
  37.  
  38. /* Start up POP receiver service */
  39. int
  40. pop1(argc,argv,p)
  41.  
  42. int argc;
  43. char *argv[];
  44. void *p;
  45.  
  46. {
  47.     struct sockaddr_in lsocket;
  48.     int s;
  49.  
  50.     if (Spop != -1) {
  51.         return 0;
  52.     }
  53.  
  54.     psignal(Curproc,0);        /* Don't keep the parser waiting */
  55.     chname(Curproc,"POP listener");
  56.  
  57.     lsocket.sin_family = AF_INET;
  58.     lsocket.sin_addr.s_addr = INADDR_ANY;
  59.     if(argc < 2)
  60.         lsocket.sin_port = IPPORT_POP;
  61.     else
  62.         lsocket.sin_port = atoi(argv[1]);
  63.  
  64.     Spop = socket(AF_INET,SOCK_STREAM,0);
  65.  
  66.     bind(Spop,(char *)&lsocket,sizeof(lsocket));
  67.  
  68.     listen(Spop,1);
  69.  
  70.     for (;;) {
  71.         if((s = accept(Spop,NULLCHAR,(int *)NULL)) == -1)
  72.             break;    /* Service is shutting down */
  73.  
  74.         /* Spawn a server */
  75.  
  76.         newproc("POP server",2048,popserv,s,NULL,NULL,0);
  77.     }
  78.     return 0;
  79. }
  80.  
  81. /* Shutdown POP service (existing connections are allowed to finish) */
  82.  
  83. int
  84. pop0(argc,argv,p)
  85. int argc;
  86. char *argv[];
  87. void *p;
  88.  
  89. {
  90.     close_s(Spop);
  91.     Spop = -1;
  92.     return 0;
  93. }
  94.  
  95. static void
  96. popserv(s,unused,p)
  97. int s;
  98. void *unused;
  99. void *p;
  100. {
  101.     struct pop_scb *scb;
  102.  
  103.     sockowner(s,Curproc);        /* We own it now */
  104.     log(s,"open POP");
  105.  
  106.     if((scb = create_scb()) == NULLSCB) {
  107.         tprintf(Nospace);
  108.         log(s,"close POP - no space");
  109.         close_s(s);
  110.         return;
  111.     }
  112.  
  113.     scb->socket = s;
  114.     scb->state  = AUTH;
  115.  
  116.     (void) usprintf(s,greeting_msg,Hostname);
  117.  
  118. loop:    if ((scb->count = recvline(s,scb->buf,BUF_LEN)) == -1){
  119.         /* He closed on us */
  120.  
  121.         goto quit;
  122.     }
  123.  
  124.     rip(scb->buf);
  125.     if (strlen(scb->buf) == 0)        /* Ignore blank cmd lines */
  126.         goto loop;
  127.     pop_sm(scb);
  128.     if (scb->state == DONE)
  129.         goto quit;
  130.  
  131.     goto loop;
  132.  
  133. quit:
  134.     log(scb->socket,"close POP");
  135.     close_s(scb->socket);
  136.     delete_scb(scb);
  137. }
  138.  
  139.  
  140. /* Create control block, initialize */
  141.  
  142. static struct
  143. pop_scb *create_scb()
  144. {
  145.     register struct pop_scb *scb;
  146.  
  147.     if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
  148.         return NULLSCB;
  149.  
  150.     scb->username[0] = '\0';
  151.     scb->msg_status = NULL;
  152.     scb->wf = NULL;
  153.  
  154.     scb->count = scb->folder_file_size = scb->msg_num = 0;
  155.  
  156.     scb->folder_modified = FALSE;
  157.     return scb;
  158. }
  159.  
  160.  
  161. /* Free resources, delete control block */
  162.  
  163. static void
  164. delete_scb(scb)
  165. register struct pop_scb *scb;
  166. {
  167.  
  168.     if (scb == NULLSCB)
  169.         return;
  170.     if (scb->wf != NULL)
  171.         fclose(scb->wf);
  172.     if (scb->msg_status  != NULL)
  173.         free((char *)scb->msg_status);
  174.  
  175.     free((char *)scb);
  176. }
  177.  
  178. /* replace terminating end of line marker(s) (\r and \n) with null */
  179. void
  180. rrip(s)
  181. register char *s;
  182. {
  183.     register char *cp;
  184.  
  185.     if((cp = strchr(s,'\r')) != NULLCHAR)
  186.         *cp = '\0';
  187.     if((cp = strchr(s,'\n')) != NULLCHAR)
  188.         *cp = '\0';
  189. }
  190.  
  191. /* --------------------- start of POP server code ------------------------ */
  192.  
  193. #define    BITS_PER_WORD        16
  194.  
  195. #define isSOM(x)        ((strncmp(x,"From ",5) == 0))
  196.  
  197. /* Command string specifications */
  198.  
  199. static char    ackd_cmd[] = "ACKD",
  200.         acks_cmd[] = "ACKS",
  201. #ifdef POP_FOLDERS
  202.         fold_cmd[] = "FOLD ",
  203. #endif
  204.         login_cmd[] = "HELO ",
  205.         nack_cmd[] = "NACK",
  206.         quit_cmd[] = "QUIT",
  207.         read_cmd[] = "READ",
  208.         retr_cmd[] = "RETR";
  209.  
  210. void
  211. pop_sm(scb)
  212. struct pop_scb *scb;
  213. {
  214.     char password[40];
  215.     void state_error(struct pop_scb *,char *);
  216.     void open_folder(struct pop_scb *);
  217.     void do_cleanup(struct pop_scb *);
  218.     void read_message(struct pop_scb *);
  219.     void retrieve_message(struct pop_scb *);
  220.     void deletemsg(struct pop_scb *,int);
  221.     void get_message(struct pop_scb *,int);
  222.     void print_message_length(struct pop_scb *);
  223.     void close_folder(struct pop_scb *);
  224. #ifdef POP_FOLDERS
  225.     void select_folder(struct pop_scb *);
  226. #endif
  227.  
  228.     if (scb == NULLSCB)    /* be certain it is good -- wa6smn */
  229.         return;
  230.  
  231.     switch(scb->state) {
  232.     case AUTH:
  233.         if (strncmp(scb->buf,login_cmd,strlen(login_cmd)) == 0){
  234.             sscanf(scb->buf,"HELO %s%s",scb->username,password);
  235.  
  236.             if (!poplogin(scb->username,password)) {
  237.                 log(scb->socket,"POP access DENIED to %s",
  238.                         scb->username);
  239.                 state_error(scb,"Access DENIED!!");
  240.                 return;
  241.             }
  242.  
  243.             log(scb->socket,"POP access granted to %s",
  244.                     scb->username);
  245.             open_folder(scb);
  246.         } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  247.             do_cleanup(scb);
  248.         } else
  249.             state_error(scb,"(AUTH) Expected HELO or QUIT command");
  250.         break;
  251.  
  252.     case MBOX:
  253.         if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  254.             read_message(scb);
  255.  
  256. #ifdef POP_FOLDERS
  257.         else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  258.             select_folder(scb);
  259.  
  260. #endif
  261.  
  262.         else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0) {
  263.             do_cleanup(scb);
  264.         } else
  265.             state_error(scb,
  266. #ifdef POP_FOLDERS
  267.                     "(MBOX) Expected FOLD, READ, or QUIT command");
  268. #else
  269.                     "(MBOX) Expected READ or QUIT command");
  270. #endif
  271.         break;
  272.  
  273.     case ITEM:
  274.         if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  275.             read_message(scb);
  276.  
  277. #ifdef POP_FOLDERS
  278.  
  279.         else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  280.             select_folder(scb);
  281. #endif
  282.  
  283.         else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  284.             retrieve_message(scb);
  285.         else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  286.             do_cleanup(scb);
  287.         else
  288.             state_error(scb,
  289. #ifdef POP_FOLDERS
  290.                "(ITEM) Expected FOLD, READ, RETR, or QUIT command");
  291. #else
  292.                "(ITEM) Expected READ, RETR, or QUIT command");
  293. #endif
  294.         break;
  295.  
  296.     case NEXT:
  297.         if (strncmp(scb->buf,ackd_cmd,strlen(ackd_cmd)) == 0){
  298.                 /* ACKD processing */
  299.             deletemsg(scb,scb->msg_num);
  300.             scb->msg_num++;
  301.             get_message(scb,scb->msg_num);
  302.         } else if (strncmp(scb->buf,acks_cmd,strlen(acks_cmd)) == 0){
  303.                 /* ACKS processing */
  304.             scb->msg_num++;
  305.             get_message(scb,scb->msg_num);
  306.         } else if (strncmp(scb->buf,nack_cmd,strlen(nack_cmd)) == 0){
  307.                 /* NACK processing */
  308.             fseek(scb->wf,scb->curpos,SEEK_SET);
  309.         } else {
  310.             state_error(scb,"(NEXT) Expected ACKD, ACKS, or NACK command");
  311.             return;
  312.         }
  313.  
  314.         print_message_length(scb);
  315.         scb->state  = ITEM;
  316.         break;
  317.  
  318.     case DONE:
  319.         do_cleanup(scb);
  320.         break;
  321.  
  322.     default:
  323.         state_error(scb,"(TOP) State Error!!");
  324.         break;
  325.     }
  326. }
  327.  
  328. void
  329. do_cleanup(scb)
  330. struct pop_scb *scb;
  331. {
  332.     void close_folder(struct pop_scb *);
  333.  
  334.     close_folder(scb);
  335.     (void) usprintf(scb->socket,signoff_msg);
  336.     scb->state = DONE;
  337. }
  338.  
  339. void
  340. state_error(scb,msg)
  341. struct pop_scb *scb;
  342. char *msg;
  343. {
  344.     (void) usprintf(scb->socket,error_rsp,msg);
  345.     scb->state = DONE;
  346. }
  347.  
  348. #ifdef POP_FOLDERS
  349.  
  350. select_folder(scb)
  351. struct pop_scb    *scb;
  352. {
  353.     sscanf(scb->buf,"FOLD %s",scb->username);
  354.  
  355.     if (scb->wf != NULL)
  356.         close_folder(scb);
  357.  
  358.     open_folder(scb);
  359. }
  360.  
  361. #endif
  362.  
  363.  
  364. void
  365. close_folder(scb)
  366. struct pop_scb *scb;
  367. {
  368.     char folder_pathname[64];
  369.     char line[BUF_LEN];
  370.     FILE *fd;
  371.     int deleted = FALSE;
  372.     int msg_no = 0;
  373. #if !defined(OS2)
  374.     struct stat folder_stat;
  375. #else
  376.    FILESTATUS3 folder_stat;
  377. #endif
  378.     int newmail(struct pop_scb *);
  379.     int isdeleted(struct pop_scb *,int);
  380.  
  381.     if (scb->wf == NULL)
  382.         return;
  383.  
  384.     if (!scb->folder_modified) {
  385.         /* no need to re-write the folder if we have not modified it */
  386.  
  387.         fclose(scb->wf);
  388.         scb->wf = NULL;
  389.  
  390.         free((char *)scb->msg_status);
  391.         scb->msg_status = NULL;
  392.         return;
  393.     }
  394.  
  395.  
  396.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  397.  
  398.     if (newmail(scb)) {
  399.         /* copy new mail into the work file and save the
  400.            message count for later */
  401.  
  402.         if ((fd = fopen(folder_pathname,"r")) == NULL) {
  403.             state_error(scb,"Unable to add new mail to folder");
  404.             return;
  405.         }
  406.  
  407.         fseek(scb->wf,0,SEEK_END);
  408.         fseek(fd,scb->folder_file_size,SEEK_SET);
  409.         while (!feof(fd)) {
  410.             fgets(line,BUF_LEN,fd);
  411.             fputs(line,scb->wf);
  412.         }
  413.  
  414.         fclose(fd);
  415.     }
  416.  
  417.     /* now create the updated mail folder */
  418.  
  419.     if ((fd = fopen(folder_pathname,"w")) == NULL){
  420.         state_error(scb,"Unable to update mail folder");
  421.         return;
  422.     }
  423.  
  424.     rewind(scb->wf);
  425.     while (!feof(scb->wf)){
  426.         fgets(line,BUF_LEN,scb->wf);
  427.  
  428.         if (isSOM(line)){
  429.             msg_no++;
  430.             if (msg_no <= scb->folder_len)
  431.                 deleted = isdeleted(scb,msg_no);
  432.             else
  433.                 deleted = FALSE;
  434.         }
  435.  
  436.         if (deleted)
  437.             continue;
  438.  
  439.         fputs(line,fd);
  440.     }
  441.  
  442.     fclose(fd);
  443.  
  444.     /* trash the updated mail folder if it is empty */
  445. #if !defined(OS2)
  446.     if ((stat(folder_pathname,&folder_stat) == 0) && (folder_stat.st_size == 0))
  447. #else
  448.     if ((stat(folder_pathname,&folder_stat) == 0) && (folder_stat.cbFile == 0))
  449. #endif
  450.         remove(folder_pathname);
  451.  
  452.     fclose(scb->wf);
  453.     scb->wf = NULL;
  454.  
  455.     free((char *)scb->msg_status);
  456.     scb->msg_status = NULL;
  457. }
  458.  
  459. void
  460. open_folder(scb)
  461. struct pop_scb    *scb;
  462. {
  463.     char folder_pathname[64];
  464.     char line[BUF_LEN];
  465.     FILE *fd;
  466.     FILE *tmpfile();
  467. #if !defined(OS2)
  468.     struct stat folder_stat;
  469. #else
  470.    FILESTATUS3 folder_stat;
  471. #endif
  472.  
  473.  
  474.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  475.     scb->folder_len       = 0;
  476.     scb->folder_file_size = 0;
  477.     if (stat(folder_pathname,&folder_stat)){
  478.          (void) usprintf(scb->socket,no_mail_rsp);
  479.          return;
  480.     }
  481. #if !defined(OS2)
  482.     scb->folder_file_size = folder_stat.st_size;
  483. #esle
  484.     scb->folder_file_size = folder_stat.cbFile;
  485. #endif
  486.     if ((fd = fopen(folder_pathname,"r")) == NULL){
  487.         state_error(scb,"Unable to open mail folder");
  488.         return;
  489.     }
  490.  
  491.     if ((scb->wf = tmpfile()) == NULL) {
  492.         state_error(scb,"Unable to create work folder");
  493.         return;
  494.     }
  495.  
  496.     while(!feof(fd)) {
  497.         fgets(line,BUF_LEN,fd);
  498.  
  499.         /* scan for begining of a message */
  500.  
  501.         if (isSOM(line))
  502.             scb->folder_len++;
  503.  
  504.         /* now put  the line in the work file */
  505.  
  506.         fputs(line,scb->wf);
  507.     }
  508.  
  509.     fclose(fd);
  510.  
  511.     scb->msg_status_size = (scb->folder_len) / BITS_PER_WORD;
  512.  
  513.     if ((((scb->folder_len) % BITS_PER_WORD) != 0) ||
  514.         (scb->msg_status_size == 0))
  515.         scb->msg_status_size++;
  516.  
  517.     if ((scb->msg_status = (unsigned int *) callocw(scb->msg_status_size,
  518.                 sizeof(unsigned int))) == NULL) {
  519.         state_error(scb,"Unable to create message status array");
  520.         return;
  521.     }
  522.  
  523.     (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  524.  
  525.     scb->state  = MBOX;
  526. }
  527.  
  528. void
  529. read_message(scb)
  530. struct pop_scb    *scb;
  531. {
  532.     void get_message(struct pop_scb *,int);
  533.     void print_message_length(struct pop_scb *);
  534.  
  535.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  536.         return;
  537.     if (scb->buf[sizeof(read_cmd) - 1] == ' ')
  538.         scb->msg_num = atoi(&(scb->buf[sizeof(read_cmd) - 1]));
  539.     else
  540.         scb->msg_num++;
  541.  
  542.     get_message(scb,scb->msg_num);
  543.     print_message_length(scb);
  544.     scb->state  = ITEM;
  545. }
  546.  
  547. void
  548. retrieve_message(scb)
  549. struct pop_scb    *scb;
  550. {
  551.     char line[BUF_LEN];
  552.     long cnt;
  553.     void rrip(char *);
  554.  
  555.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  556.         return;
  557.     if (scb->msg_len == 0) {
  558.         state_error(scb,"Attempt to access a DELETED message!");
  559.         return;
  560.     }
  561.  
  562.     cnt  = scb->msg_len;
  563.     while(!feof(scb->wf) && (cnt > 0)) {
  564.         fgets(line,BUF_LEN,scb->wf);
  565.         rrip(line);
  566.  
  567.         (void) usprintf(scb->socket,msg_line,line);
  568.         cnt -= (strlen(line)+2);    /* Compensate for CRLF */
  569.     }
  570.  
  571.     scb->state = NEXT;
  572. }
  573.  
  574. void
  575. get_message(scb,msg_no)
  576. struct pop_scb    *scb;
  577. int msg_no;
  578. {
  579.     char line[BUF_LEN];
  580.     long ftell();
  581.     void rrip(char *);
  582.  
  583.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  584.         return;
  585.     scb->msg_len = 0;
  586.     if (msg_no > scb->folder_len) {
  587.         scb->curpos  = 0;
  588.         scb->nextpos = 0;
  589.         return;
  590.     } else {
  591.         /* find the message and its length */
  592.  
  593.         rewind(scb->wf);
  594.         while (!feof(scb->wf) && (msg_no > -1)) {
  595.             if (msg_no > 0)
  596.                 scb->curpos = ftell(scb->wf);
  597.             
  598.             fgets(line,BUF_LEN,scb->wf);
  599.             rrip(line);
  600.  
  601.             if (isSOM(line))
  602.                 msg_no--;
  603.  
  604.             if (msg_no != 0)
  605.                 continue;
  606.  
  607.             scb->nextpos  = ftell(scb->wf);
  608.             scb->msg_len += (strlen(line)+2);    /* Add CRLF */
  609.         }
  610.     }
  611.  
  612.     if (scb->msg_len > 0)
  613.         fseek(scb->wf,scb->curpos,SEEK_SET);
  614.  
  615.     /* we need the pointers even if the message was deleted */
  616.  
  617.     if  (isdeleted(scb,scb->msg_num))
  618.         scb->msg_len = 0;
  619. }
  620.  
  621. static int
  622. poplogin(username,pass)
  623. char *pass;
  624. char *username;
  625. {
  626.     char buf[80];
  627.     char *cp;
  628.     char *cp1;
  629.     FILE *fp;
  630.  
  631.     if((fp = fopen(Popusers,"r")) == NULLFILE) {
  632.         /* User file doesn't exist */
  633.         tprintf("POP users file %s not found\n",Popusers);
  634.         return(FALSE);
  635.     }
  636.  
  637.     while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  638.         if(buf[0] == '#')
  639.             continue;    /* Comment */
  640.  
  641.         if((cp = strchr(buf,':')) == NULLCHAR)
  642.             /* Bogus entry */
  643.             continue;
  644.  
  645.         *cp++ = '\0';        /* Now points to password */
  646.         if(strcmp(username,buf) == 0)
  647.             break;        /* Found user name */
  648.     }
  649.  
  650.     if(feof(fp)) {
  651.         /* User name not found in file */
  652.  
  653.         fclose(fp);
  654.         return(FALSE);
  655.     }
  656.     fclose(fp);
  657.  
  658.     if ((cp1 = strchr(cp,':')) == NULLCHAR)
  659.         return(FALSE);
  660.  
  661.     *cp1 = '\0';
  662.     if(strcmp(cp,pass) != 0) {
  663.         /* Password required, but wrong one given */
  664.  
  665.         return(FALSE);
  666.     }
  667.  
  668.     /* whew! finally made it!! */
  669.  
  670.     return(TRUE);
  671. }
  672.  
  673. int
  674. isdeleted(scb,msg_no)
  675. struct pop_scb *scb;
  676. int msg_no;
  677. {
  678.     unsigned int mask = 1,offset;
  679.  
  680.     msg_no--;
  681.     offset = msg_no / BITS_PER_WORD;
  682.     mask <<= msg_no % BITS_PER_WORD;
  683.     return (((scb->msg_status[offset]) & mask)? TRUE:FALSE);
  684. }
  685.  
  686. void
  687. deletemsg(scb,msg_no)
  688. struct pop_scb *scb;
  689. int msg_no;
  690. {
  691.     unsigned int mask = 1,offset;
  692.  
  693.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  694.         return;
  695.     msg_no--;
  696.     offset = msg_no / BITS_PER_WORD;
  697.     mask <<= msg_no % BITS_PER_WORD;
  698.     scb->msg_status[offset] |= mask;
  699.     scb->folder_modified = TRUE;
  700. }
  701.  
  702. int
  703. newmail(scb)
  704. struct pop_scb *scb;
  705. {
  706.     char folder_pathname[64];
  707. #if !defined(OS2)
  708.     struct stat folder_stat;
  709. #else
  710.    FILESTATUS3 folder_stat;
  711. #endif
  712.  
  713.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  714.     if (stat(folder_pathname,&folder_stat)) {
  715.         state_error(scb,"Unable to get old mail folder's status");
  716.         return(FALSE);
  717.     } else
  718. #if !defined(OS2)
  719.         return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  720. #else
  721.         return ((folder_stat.cbFile > scb->folder_file_size)? TRUE:FALSE);
  722. #endif
  723. }
  724.  
  725. void
  726. print_message_length(scb)
  727. struct pop_scb *scb;
  728. {
  729.     char *print_control_string;
  730.  
  731.     if (scb == NULLSCB)    /* check for null -- wa6smn */
  732.         return;
  733.     if (scb->msg_len > 0)
  734.         print_control_string = length_rsp;
  735.     else if (scb->msg_num <= scb->folder_len)
  736.         print_control_string = length_rsp;
  737.     else
  738.         print_control_string = no_more_rsp;
  739.  
  740.     (void)usprintf(scb->socket,print_control_string,scb->msg_len,scb->msg_num);
  741. }
  742.